package com.example.demo.common.util;

import org.apache.commons.lang3.StringUtils;
import org.apache.poi.xwpf.usermodel.VerticalAlign;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;

import java.math.BigInteger;
import java.util.HashMap;
import java.util.Map;

//文本构建器
public class XWPFRunBuilder {

    private XWPFRun run = null;
    private Map<String, CTRPr> savedRPr;

    public XWPFRunBuilder init(XWPFParagraph paragraph) {
        return init(paragraph, false);
    }

    public XWPFRunBuilder init(XWPFParagraph paragraph, boolean newLine) {
        this.run = paragraph.createRun();
        if(newLine) {
            run.addBreak();
        }
        return this;
    }

    public XWPFRunBuilder init(XWPFParagraph paragraph, int pos) {
        this.run = paragraph.insertNewRun(pos);
        if(this.run == null) {
            return init(paragraph, false);
        }
        return this;
    }

    public XWPFRunBuilder init(XWPFRun run) {
        if(run == null) {
            throw new IllegalArgumentException("the run should not be null");
        }
        this.run = run;
        return this;
    }

    public XWPFRunBuilder content(String content){
        ensureInit();
        if(StringUtils.isNotEmpty(content)){
            if(content.contains("\n")){
                String[] lines = content.split("\n");
                run.setText(lines[0], 0);
                for (int i = 0; i < lines.length; i++) {
                    //换行
                    run.addBreak();
                    //写入数据
                    run.setText(lines[i]);
                }
            } else{
                run.setText(content, 0);
            }
        }
        return this;
    }

    //加粗
    public XWPFRunBuilder bold(boolean bold) {
        ensureInit();
        run.setBold(bold);
        return this;
    }

    //斜体
    public XWPFRunBuilder italic(boolean italic) {
        ensureInit();
        run.setItalic(italic);
        return this;
    }

    //删除线
    public XWPFRunBuilder strike(boolean strike) {
        ensureInit();
        run.setStrike(strike);
        return this;
    }

    //字体设置，中文字体、英文字体、字号
    public XWPFRunBuilder font(String cnFontFamily, String enFontFamily, String fontSize) {
        ensureInit();
        CTRPr rPr = getPrOfRun(run);
        //设置字体
        CTFonts fonts = rPr.isSetRFonts() ? rPr.getRFonts() : rPr.addNewRFonts();
        if(StringUtils.isNotEmpty(enFontFamily)){
            fonts.setAscii(enFontFamily);
            fonts.setHAnsi(enFontFamily);
        }
        if(StringUtils.isNotEmpty(cnFontFamily)){
            fonts.setEastAsia(cnFontFamily);
            fonts.setHint(STHint.EAST_ASIA);
        }
        //设置字体大小
        CTHpsMeasure sz = rPr.isSetSz() ? rPr.getSz() : rPr.addNewSzCs();
        sz.setVal(new BigInteger(fontSize));
        CTHpsMeasure szCs = rPr.isSetSzCs() ? rPr.getSzCs() : rPr.addNewSzCs();
        szCs.setVal(new BigInteger(fontSize));
        return this;
    }

    public XWPFRunBuilder shade(STShd.Enum shdStyle, String shdColor) {
        ensureInit();
        CTRPr rPr = getPrOfRun(run);
        //设置底纹
        CTShd shd = rPr.isSetShd() ? rPr.getShd() : rPr.addNewShd();
        if(shdStyle != null) {
            shd.setVal(shdStyle);
        }
        if(shdColor != null) {
            shd.setColor(shdColor);
            shd.setFill(shdColor);
        }
        return this;
    }

    //字符垂直方向上间距位置：>0提升 <0降低 =磅值*2
    public XWPFRunBuilder position(int position) {
        ensureInit();
        if(position != 0) {
            run.setTextPosition(position);
        }
        return this;
    }

    //字符间距
    public XWPFRunBuilder space(int spacingValue) {
        ensureInit();
        if(spacingValue > 0) {
            CTRPr rPr = getPrOfRun(run);
            CTSignedTwipsMeasure measure = rPr.isSetSpacing() ? rPr.getSpacing() : rPr.addNewSpacing();
            measure.setVal(new BigInteger(String.valueOf(spacingValue)));
        }
        return this;
    }

    //SUPERSCRIPT：上标；SUBSCRIPT：下标
    public XWPFRunBuilder verticalAlign(VerticalAlign verticalAlign) {
        ensureInit();
        if(verticalAlign != null) {
            run.setSubscript(verticalAlign);
        }
        return this;
    }

    //下划线
    public XWPFRunBuilder underLine(STUnderline.Enum underStyle, String underLineColor) {
        ensureInit();
        CTRPr rPr = getPrOfRun(run);
        CTUnderline udLine = rPr.addNewU();
        udLine.setVal(underStyle);
        udLine.setColor(underLineColor);
        return this;
    }

    //高亮
    public XWPFRunBuilder highLight(STHighlightColor.Enum highStyle) {
        ensureInit();
        CTRPr rPr = getPrOfRun(run);
        if(highStyle != null){
            CTHighlight highLight = rPr.isSetHighlight() ? rPr.getHighlight() : rPr.addNewHighlight();
            highLight.setVal(highStyle);
        }
        return this;
    }

    public XWPFRunBuilder savePr(String rPrName) {
        ensureInit();
        if(savedRPr == null){
            savedRPr = new HashMap<String, CTRPr>();
        }
        savedRPr.put(rPrName, getPrOfRun(run));
        return this;
    }

    public XWPFRunBuilder samePrOf(String rPrName) {
        ensureInit();
        if(savedRPr != null && savedRPr.containsKey(rPrName)){
            return samePrOf(savedRPr.get(rPrName));
        }
        return this;
    }

    public XWPFRunBuilder samePrOf(CTRPr rPr) {
        ensureInit();
        if (rPr != null) {
            run.getCTR().setRPr(rPr);
        }
        return this;
    }

    public XWPFRunBuilder samePrOf(XWPFRun otherRun) {
        ensureInit();
        run.getCTR().setRPr(getPrOfRun(otherRun));
        return this;
    }

    public XWPFRun build() {
        return run;
    }


    //确保init方法是第一个调用的，避免出现空指针异常
    private void ensureInit(){
        if(this.run == null){
            throw new IllegalStateException("the init method must be invoked firstly");
        }
    }

    public CTRPr getPrOfRun(XWPFRun run) {
        CTRPr rPr = run.getCTR().getRPr();
        if (rPr == null) {
            rPr = run.getCTR().addNewRPr();
        }
        return rPr;
    }
}
